import pandas as pd
import numpy as np
import json
import logging
from datetime import datetime
import openai
from sklearn.metrics.pairwise import cosine_similarity
import matplotlib.pyplot as plt
import networkx as nx

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class CareerPathRecommender:
    """职业路径推荐类"""
    
    def __init__(self, config):
        self.config = config
        openai.api_key = self.config["openai_api_key"]
        openai.base_url = self.config.get("openai_base_url", "https://api.openai.com/v1/")
        self.career_graph = None
        
    def load_data(self, jobs_file, trends_file):
        """加载职位和趋势数据
        
        Args:
            jobs_file (str): 职位数据文件路径
            trends_file (str): 趋势数据文件路径
            
        Returns:
            tuple: (jobs_df, trends_df)
        """
        try:
            jobs_df = pd.read_csv(jobs_file)
            trends_df = pd.read_csv(trends_file)
            logger.info(f"加载了 {len(jobs_df)} 条职位数据和 {len(trends_df)} 条趋势数据")
            return jobs_df, trends_df
        except Exception as e:
            logger.error(f"数据加载错误: {str(e)}")
            return pd.DataFrame(), pd.DataFrame()
    
    def build_career_graph(self, jobs_df):
        """构建职业路径图
        
        Args:
            jobs_df (DataFrame): 职位数据
            
        Returns:
            networkx.DiGraph: 职业路径图
        """
        # 初始化有向图
        G = nx.DiGraph()
        
        # 提取职位标题和经验要求
        titles = jobs_df['title'].dropna().unique()
        
        # 添加节点
        for title in titles:
            # 过滤相同职位
            jobs = jobs_df[jobs_df['title'] == title]
            
            # 提取平均薪资和经验要求
            avg_salary = self._calculate_avg_salary(jobs)
            experience = self._extract_experience_level(jobs)
            
            # 添加节点，包含属性
            G.add_node(title, 
                      salary=avg_salary, 
                      experience=experience,
                      count=len(jobs))
        
        # 建立职业路径连接（根据经验等级）
        self._connect_career_paths(G)
        
        self.career_graph = G
        logger.info(f"构建了包含 {len(G.nodes)} 个职位的职业路径图")
        
        return G
    
    def _calculate_avg_salary(self, jobs_df):
        """计算平均薪资"""
        if jobs_df.empty:
            return "未知"
            
        # 处理薪资格式，如"20k-30k"
        salary_ranges = jobs_df['salary'].dropna().tolist()
        if not salary_ranges:
            return "未知"
            
        total_min = 0
        total_max = 0
        count = 0
        
        for salary in salary_ranges:
            # 解析薪资范围
            try:
                if 'k' in salary.lower() or 'K' in salary:
                    # 处理"20k-30k"格式
                    parts = salary.lower().replace('k', '').split('-')
                    if len(parts) == 2:
                        min_val = float(parts[0].strip())
                        max_val = float(parts[1].strip())
                        total_min += min_val
                        total_max += max_val
                        count += 1
            except:
                continue
                
        if count == 0:
            return "未知"
            
        avg_min = total_min / count
        avg_max = total_max / count
        
        return f"{avg_min:.1f}k-{avg_max:.1f}k"
    
    def _extract_experience_level(self, jobs_df):
        """提取经验水平"""
        # 简化的经验提取
        experience_values = jobs_df['experience'].dropna().tolist()
        
        if not experience_values:
            return 0
            
        # 简单统计最常见的经验要求
        experience_count = {}
        for exp in experience_values:
            if exp in experience_count:
                experience_count[exp] += 1
            else:
                experience_count[exp] = 1
                
        # 找出最常见的经验要求
        most_common = max(experience_count.items(), key=lambda x: x[1])[0]
        
        # 转换为数值
        if '应届' in most_common or '在校' in most_common:
            return 0
        elif '1年' in most_common or '1-3' in most_common:
            return 1
        elif '3年' in most_common or '3-5' in most_common:
            return 3
        elif '5年' in most_common or '5-10' in most_common:
            return 5
        elif '10年' in most_common:
            return 10
        else:
            return 2  # 默认值
    
    def _connect_career_paths(self, G):
        """连接职业路径"""
        # 按经验水平排序节点
        nodes_by_experience = sorted(G.nodes(data=True), key=lambda x: x[1].get('experience', 0))
        
        # 使用LLM建立职业路径连接
        for i, (title1, data1) in enumerate(nodes_by_experience):
            exp1 = data1.get('experience', 0)
            
            # 找出经验要求高于当前职位的职位
            for title2, data2 in nodes_by_experience[i+1:]:
                exp2 = data2.get('experience', 0)
                
                # 只连接经验差距合理的职位
                if 0 < exp2 - exp1 <= 3:
                    # 检查两个职位是否相关
                    if self._are_positions_related(title1, title2):
                        # 添加边，权重为经验差距
                        G.add_edge(title1, title2, weight=exp2-exp1)
    
    def _are_positions_related(self, title1, title2):
        """检查两个职位是否相关"""
        # 简单实现：检查职位名称中的关键词
        common_keywords = ["开发", "工程师", "架构", "数据", "分析", "管理", "运营", "产品"]
        
        # 检查是否有共同关键词
        for keyword in common_keywords:
            if keyword in title1 and keyword in title2:
                return True
                
        # 可以扩展为使用LLM判断职位相关性
        return False
    
    def recommend_career_paths(self, user_skills, job_skills=None, career_goals=""):
        """推荐职业发展路径
        
        Args:
            user_skills (dict): 用户技能
            job_skills (dict, optional): 职位技能要求
            career_goals (str): 职业目标描述
            
        Returns:
            list: 推荐的职业路径
        """
        try:
            # 兼容不同的数据结构
            skills_dict = {}
            
            # 处理用户技能数据的不同可能格式
            if isinstance(user_skills, dict):
                # 直接传入的是analyze_resume_and_job_together的结果
                if user_skills:  # 非空字典
                    skills_dict = user_skills  # 直接使用
                else:
                    logger.warning("user_skills是空字典")
                    skills_dict = {}
            else:
                logger.warning(f"user_skills不是字典类型: {type(user_skills)}")
                skills_dict = {}
                
            # 输出调试信息
            logger.info(f"处理后的user_skills: {skills_dict}")
            
            # 生成职业路径
            # ... 后续代码 ...
            
            logger.info("生成职业路径推荐...")
            
            # 将用户技能转换为文本格式
            skills_text = ", ".join([f"{skill}({level}分)" for skill, level in skills_dict.get('skills', {}).items()])
            
            # 提取行业趋势信息
            trending_industries = []
            if isinstance(job_skills, dict) and 'industry_growth' in job_skills:
                trending_industries = [{"industry": ind, "growth": data.get('growth_rate', 0)} 
                                      for ind, data in job_skills.get('industry_growth', {}).items()]
                trending_industries.sort(key=lambda x: x['growth'], reverse=True)
                trending_industries = trending_industries[:3]  # 取增长最快的三个行业
            
            trending_text = "; ".join([f"{item['industry']}(增长率{item['growth']:.1f}%)" for item in trending_industries])
            
            # 构建提示
            prompt = f"""
            作为职业发展规划专家，请根据以下信息为用户推荐3条具体的职业发展路径：
            
            用户当前技能: {skills_text}
            
            行业增长趋势: {trending_text}
            
            用户职业目标: {career_goals}
            
            请为每条路径提供以下信息:
            1. 路径名称
            2. 起点职位、中间职位和目标职位
            3. 每个职位所需关键技能
            4. 每一步需要提升的能力
            5. 预计所需时间
            6. 该路径的优势和挑战
            
            以JSON格式返回，结构如下：
            {{
                "paths": [
                    {{
                        "name": "路径名称",
                        "positions": [
                            {{
                                "title": "职位名称",
                                "is_current": true/false,
                                "required_skills": ["技能1", "技能2"],
                                "time_required": "所需时间描述"
                            }},
                            ...
                        ],
                        "advantages": ["优势1", "优势2"],
                        "challenges": ["挑战1", "挑战2"]
                    }},
                    ...
                ]
            }}
            
            确保路径符合用户的技能背景和行业发展趋势，并提供实际可行的建议。
            """
            
            response = openai.chat.completions.create(
                model=self.config["llm_model"],
                messages=[
                    {"role": "system", "content": "你是一位专业的职业规划顾问，擅长分析用户技能和行业趋势，提供个性化的职业发展路径建议。"},
                    {"role": "user", "content": prompt}
                ],
                temperature=0.7,
                response_format={"type": "json_object"}
            )
            
            # 解析回复
            result = json.loads(response.choices[0].message.content)
            paths = result.get('paths', [])
            
            # 确保至少有一条路径
            if not paths:
                # 生成默认路径
                paths = [self._generate_default_path(skills_dict, career_goals)]
            
            logger.info(f"成功生成 {len(paths)} 条职业路径推荐")
            return paths
            
        except Exception as e:
            logger.error(f"职业路径推荐生成错误: {str(e)}")
            # 出错时返回默认路径
            return [self._generate_default_path(skills_dict, career_goals)]
    
    def _generate_default_path(self, user_skills, career_goals):
        """生成默认路径（出错时使用）"""
        # 从用户技能中提取最强的三个技能
        top_skills = sorted(
            user_skills.get('skills', {}).items(), 
            key=lambda x: x[1], 
            reverse=True
        )[:3]
        top_skills = [skill for skill, _ in top_skills]
        
        # 构造一个基本的职业路径
        default_path = {
            "name": "基于当前技能的发展路径",
            "positions": [
                {
                    "title": "当前职位",
                    "is_current": True,
                    "required_skills": top_skills,
                    "time_required": "当前"
                },
                {
                    "title": "中级职位",
                    "is_current": False,
                    "required_skills": top_skills + ["沟通能力", "项目管理"],
                    "time_required": "1-2年"
                },
                {
                    "title": "目标职位",
                    "is_current": False,
                    "required_skills": top_skills + ["领导力", "战略思维", "决策能力"],
                    "time_required": "3-5年"
                }
            ],
            "advantages": ["基于您现有的技能优势", "循序渐进的成长路径"],
            "challenges": ["需要持续学习新技能", "可能需要跨领域发展"]
        }
        
        return default_path
    
    def visualize_career_path(self, path, output_path=None):
        """可视化职业路径
        
        Args:
            path (list): 职业路径
            output_path (str, optional): 输出图片路径
            
        Returns:
            str: 图片保存路径或None
        """
        if not self.career_graph or not path or len(path) < 2:
            logger.error("无效的职业路径或图未构建")
            return None
            
        try:
            # 创建子图
            sub_nodes = set(path)
            
            # 添加相关节点（可选）
            for node in path:
                neighbors = list(self.career_graph.successors(node)) + list(self.career_graph.predecessors(node))
                for neighbor in neighbors:
                    if len(sub_nodes) < 15:  # 限制节点数量
                        sub_nodes.add(neighbor)
            
            # 创建子图
            sub_graph = self.career_graph.subgraph(sub_nodes)
            
            # 设置绘图
            plt.figure(figsize=(12, 8))
            pos = nx.spring_layout(sub_graph, seed=42)
            
            # 绘制所有节点和边
            nx.draw_networkx_nodes(sub_graph, pos, node_size=2000, node_color='lightblue', alpha=0.8)
            nx.draw_networkx_edges(sub_graph, pos, width=1.0, alpha=0.5, arrows=True)
            
            # 高亮路径
            path_edges = list(zip(path[:-1], path[1:]))
            nx.draw_networkx_nodes(sub_graph, pos, nodelist=path, node_size=2000, node_color='lightgreen')
            nx.draw_networkx_edges(sub_graph, pos, edgelist=path_edges, width=3.0, edge_color='green', arrows=True)
            
            # 添加标签
            labels = {}
            for node in sub_nodes:
                # 添加薪资信息
                salary = self.career_graph.nodes[node].get('salary', '')
                labels[node] = f"{node}\n{salary}"
                
            nx.draw_networkx_labels(sub_graph, pos, labels=labels, font_size=10, font_weight='bold')
            
            # 添加标题
            plt.title("职业发展路径图", fontsize=15)
            plt.axis('off')
            
            # 保存图片
            if output_path:
                plt.savefig(output_path, dpi=300, bbox_inches='tight')
                logger.info(f"职业路径图已保存至 {output_path}")
            else:
                timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
                output_path = f"data/career_path_{timestamp}.png"
                plt.savefig(output_path, dpi=300, bbox_inches='tight')
                
            plt.close()
            return output_path
            
        except Exception as e:
            logger.error(f"职业路径可视化错误: {str(e)}")
            return None 